﻿using System;
using System.Runtime.InteropServices;
using System.Security;

using RPC_AUTH_IDENTITY_HANDLE = System.IntPtr;
using DWORD = System.UInt32;
using HANDLE = System.IntPtr;
using ULONG = System.UInt32;
using USHORT = System.UInt16;
using UUID = System.Guid;
using USN = System.Int64;
using LPVOID = System.IntPtr;
using PSID = System.IntPtr;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;

namespace ActiveDirectoryUtilities.CommonLibrary.Unsafe
{
	static public class NetApi32
	{
		[StructLayout(LayoutKind.Sequential)]
		public sealed class DS_DOMAIN_TRUSTS
		{
			//Must keep below in order to match DS_DOMAIN_TRUSTS struct
			[MarshalAs(UnmanagedType.LPTStr)]
			public string NetbiosDomainName;
			[MarshalAs(UnmanagedType.LPTStr)]
			public string DnsDomainName;
			public DS_DOMAIN Flags;
			private int ParentIndex;
			public TRUST_TYPE TrustType;
			public TRUST_ATTRIBUTE TrustAttributes;
			public PSID DomainSid;
			public Guid DomainGuid;
			//End sensitive area.
		}

		/// <summary>
		/// Flags for the DS_DOMAIN_TRUSTS structure.
		/// <para>http://msdn.microsoft.com/en-us/library/ms676059(VS.85).aspx</para>
		/// </summary>
		[FlagsAttribute]
		public enum DS_DOMAIN : int
		{
			IN_FOREST = 0x1,
			DIRECT_OUTBOUND = 0x2,
			TREE_ROOT = 0x4,
			PRIMARY = 0x8,
			NATIVE_MODE = 0x10,
			DIRECT_INBOUND = 0x20,
			ALL = DS_DOMAIN.IN_FOREST | DS_DOMAIN.DIRECT_OUTBOUND | DS_DOMAIN.TREE_ROOT
				| DS_DOMAIN.PRIMARY | DS_DOMAIN.NATIVE_MODE | DS_DOMAIN.DIRECT_INBOUND
		};

		/// <summary>
		/// Integer value that represents the type of the trust
		/// <para>http://msdn.microsoft.com/en-us/library/cc223771.aspx </para>
		/// </summary>
		public enum TRUST_TYPE
		{
			DOWNLEVEL = 1,
			UPLEVEL = 2,
			MIT = 3,
			DCE_DEPRECATED = 4
		};

		/// <summary>
		/// Bit flag that represents the attributes of the trust.
		/// <para>http://msdn.microsoft.com/en-us/library/cc223779.aspx</para>
		/// </summary>
		[Flags]
		public enum TRUST_ATTRIBUTE : int
		{
			NON_TRANSITIVE = 0x1,
			UPLEVEL_ONLY = 0x2,
			QUARANTINED_DOMAIN = 0x4,
			FOREST_TRANSITIVE = 0x8,
			CROSS_ORGANIZATION = 0x10,
			WITHIN_FOREST = 0x20,
			TREAT_AS_EXTERNAL = 0x40,
			USES_RC4_ENCRYPTION = 0x80,
			BIT_8_DEPRECATED_SHOULD_BE_0 = 0x100,
			BIT_22_DEPRECATED_SHOULD_BE_0 = 0x400000,
			BIT_23_DEPRECATED_SHOULD_BE_0 = 0x800000,
			BIT_24_RESERVED_SHOULD_BE_0 = 0x1000000
		};

		/// <summary>
		/// http://msdn.microsoft.com/en-us/library/ms675983.aspx
		/// </summary>
		[Flags]
		public enum DsGetDcFlags : long
		{
			FORCE_REDISCOVERY = 0x00000001,
			DIRECTORY_SERVICE_REQUIRED = 0x00000010,
			DIRECTORY_SERVICE_PREFERRED = 0x00000020,
			GC_SERVER_REQUIRED = 0x00000040,
			PDC_REQUIRED = 0x00000080,
			BACKGROUND_ONLY = 0x00000100,
			IP_REQUIRED = 0x00000200,
			KDC_REQUIRED = 0x00000400,
			TIMESERV_REQUIRED = 0x00000800,
			WRITABLE_REQUIRED = 0x00001000,
			GOOD_TIMESERV_PREFERRED = 0x00002000,
			AVOID_SELF = 0x00004000,
			ONLY_LDAP_NEEDED = 0x00008000,
			IS_FLAT_NAME = 0x00010000,
			IS_DNS_NAME = 0x00020000,
			TRY_NEXTCLOSEST_SITE = 0x00040000,
			DIRECTORY_SERVICE_6_REQUIRED = 0x00080000,
			RETURN_DNS_NAME = 0x40000000,
			RETURN_FLAT_NAME = 0x80000000
		}

		public static DWORD DsEnumerateDomainTrusts(string ServerName, DS_DOMAIN Flags, out DS_DOMAIN_TRUSTS[] Domains)
		{
			DWORD errorCode = 0;
			ULONG count = 0;
			IntPtr internalDomainList = IntPtr.Zero;
			List<DS_DOMAIN_TRUSTS> tempDomains = new List<DS_DOMAIN_TRUSTS>();
			errorCode = NetApi32.DsEnumerateDomainTrusts(ServerName, (ULONG)Flags, out internalDomainList, out count);
			if (errorCode != 0)
			{
				throw new Win32Exception((Int32)errorCode);
			}

			if ((internalDomainList != IntPtr.Zero) && (count != 0))
			{
				IntPtr ptr = IntPtr.Zero;
				for (int i = 0; i < count; i++)
				{
					ptr = (IntPtr)(((long)internalDomainList) + (i * Marshal.SizeOf(typeof(DS_DOMAIN_TRUSTS))));
					DS_DOMAIN_TRUSTS structure = new DS_DOMAIN_TRUSTS();
					Marshal.PtrToStructure(ptr, structure);
					tempDomains.Add(structure);
				}
			}
			Domains = tempDomains.ToArray();
			NetApi32.NetApiBufferFree(internalDomainList);
			return errorCode;
		}

		/// <summary>
		/// http://msdn.microsoft.com/en-us/library/ms675976(VS.85).aspx
		/// </summary>
		/// <param name="serverName"></param>
		/// <param name="flags"></param>
		/// <param name="domains"></param>
		/// <param name="count"></param>
		/// <returns></returns>
		[DllImport("Netapi32.dll", CharSet = CharSet.Auto, EntryPoint = "DsEnumerateDomainTrusts", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		private static extern DWORD DsEnumerateDomainTrusts(
			[MarshalAs(UnmanagedType.LPTStr)] string ServerName
			, ULONG Flags
			, out IntPtr Domains
			, out ULONG Count
			);

		/// <summary>
		/// http://msdn.microsoft.com/en-us/library/aa370304(VS.85).aspx
		/// </summary>
		/// <param name="buffer"></param>
		/// <returns></returns>
		[DllImport("Netapi32.dll", CharSet = CharSet.Auto, EntryPoint = "NetApiBufferFree", SetLastError = false, ThrowOnUnmappableChar = true), SuppressUnmanagedCodeSecurity]
		private static extern DWORD NetApiBufferFree(
			LPVOID buffer
			);
	}
}
